package hu.bme.aut.consulttime.server.entityservices;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.TypedQuery;

import hu.bme.aut.consulttime.client.ToDoService;
import hu.bme.aut.consulttime.entitydtos.ToDoDTO;
import hu.bme.aut.consulttime.server.email.EmailProvider;
import hu.bme.aut.consulttime.server.entities.Student;
import hu.bme.aut.consulttime.server.entities.Team;
import hu.bme.aut.consulttime.server.entities.ToDo;
import hu.bme.aut.consulttime.server.entities.Tutor;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class ToDoServiceImpl extends RemoteServiceServlet implements ToDoService{

	private static final long serialVersionUID = 567344004292568791L;

	public static final EntityManager entityManager() {
		return EntityManagerFactoryWrapper.get().createEntityManager();
	}
	
	@Override
	public Boolean createToDo(ToDoDTO toDoDTO) {

		EntityManager em = entityManager();
		EntityTransaction tx = em.getTransaction();

		ToDo todo = new ToDo();
		todo.setTitle(toDoDTO.getTitle());
		todo.setDate(toDoDTO.getDate());
		todo.setDescription(toDoDTO.getDescription());
		todo.setWeek(toDoDTO.getWeek());

		try {
			tx.begin();
			todo.setTeam(em.find(Team.class, toDoDTO.getTeamId()));
			todo.setStudent(em.find(Student.class, toDoDTO.getStudentId()));
			todo.setTutor(em.find(Tutor.class, toDoDTO.getTutorId()));
			em.persist(todo);
			tx.commit();
		} 
		catch (Throwable t) {
			t.printStackTrace();
			tx.rollback();
			return false;
		} 
		finally {
			em.close();
		}
		
		try {
			
			if (todo.getStudent().isEmailNotification()) {
				
				String emailAddress = todo.getStudent().getEmail();
				String subject = "New to-do on ConsultTime!";
				String body = "Tutor: " + todo.getTutor().getFirstName() + " " + todo.getTutor().getLastName() + " (" + todo.getTutor().getUserName() + ")\n";
				body = body + "Project: " + todo.getTeam().getProject().getTitle() + "\n";
				body = body + "Team: " + todo.getTeam().getName() + "\n";
				body = body + "Student: " + todo.getStudent().getFirstName() + " " + todo.getStudent().getLastName() + " (" + todo.getStudent().getUserName() + ")\n\n";
				body = body + "To-do: \n";
				body = body + "Date: " + todo.getDate().toString() + "\n";
				body = body + "Title: " + todo.getTitle() + "\n";
				body = body + "Week: " + String.valueOf(todo.getWeek()) + "\n\n";
				body = body + todo.getDescription();
				
				EmailProvider.sendEmail(emailAddress, subject, body);
			}
		} catch (Throwable t) {
			t.printStackTrace();
		}
		
		return true;
	}
	
	@Override
	public ToDoDTO retrieveToDo(long toDoId) {

		EntityManager em = entityManager();
		ToDo toDo = null;

		try {
			toDo = em.find(ToDo.class, toDoId);
		}
		catch (Throwable t) {
			t.printStackTrace();
		}
		finally {
			em.close();
		}

		return createToDoDTO(toDo);
	}    
	
	@Override
	public List<ToDoDTO> retrieveToDos(long teamId) {

		EntityManager em = entityManager();
		List<ToDo> toDos = null; 

		try {
			TypedQuery<ToDo> query = em.createQuery("select t from ToDo t where t.team.teamId = ?1", ToDo.class);
			query.setParameter(1, teamId);
			toDos = query.getResultList();
		}
		catch (Throwable t) {
			t.printStackTrace();
		}
		finally {
			em.close();
		}

		List<ToDoDTO> toDoDTOs = new ArrayList<ToDoDTO>(toDos != null ? toDos.size() : 0);
	    if (toDos != null) {
	      for (ToDo toDo : toDos) {
	        toDoDTOs.add(createToDoDTO(toDo));
	      }
	    }
		
		return toDoDTOs;
	}
	
	@Override	
	public List<ToDoDTO> retrieveToDosForStudent(long studentId, long teamId) {

		EntityManager em = entityManager();
		List<ToDo> toDos = null; 

		try {
			TypedQuery<ToDo> query = em.createQuery("select t from ToDo t where t.student.userId = ?1 AND t.team.teamId = ?2", ToDo.class);
			query.setParameter(1, studentId);
			query.setParameter(2, teamId);
			toDos = query.getResultList();
		}
		catch (Throwable t) {
			t.printStackTrace();
		}
		finally {
			em.close();
		}

		List<ToDoDTO> toDoDTOs = new ArrayList<ToDoDTO>(toDos != null ? toDos.size() : 0);
	    if (toDos != null) {
	      for (ToDo toDo : toDos) {
	        toDoDTOs.add(createToDoDTO(toDo));
	      }
	    }
		
		return toDoDTOs;
	}
	
	@Override	
	public List<ToDoDTO> retrieveToDosByTutor(long tutorId, long teamId) {

		EntityManager em = entityManager();
		List<ToDo> toDos = null; 

		try {
			TypedQuery<ToDo> query = em.createQuery("select t from ToDo t where t.tutor.userId = ?1 AND t.team.teamId = ?2", ToDo.class);
			query.setParameter(1, tutorId);
			query.setParameter(2, teamId);
			toDos = query.getResultList();
		}
		catch (Throwable t) {
			t.printStackTrace();
		}
		finally {
			em.close();
		}

		List<ToDoDTO> toDoDTOs = new ArrayList<ToDoDTO>(toDos != null ? toDos.size() : 0);
	    if (toDos != null) {
	      for (ToDo toDo : toDos) {
	        toDoDTOs.add(createToDoDTO(toDo));
	      }
	    }
		
		return toDoDTOs;
	}
	
	@Override
	public Boolean updateToDo(ToDoDTO toDoDTO) {

		EntityManager em = entityManager();
		EntityTransaction tx = em.getTransaction();
		ToDo todo = null;
		
		try {
			tx.begin();

			todo = em.find(ToDo.class, toDoDTO.getTodoId());
			todo.setTitle(toDoDTO.getTitle());
			todo.setDate(toDoDTO.getDate());
			todo.setDescription(toDoDTO.getDescription());
			todo.setWeek(toDoDTO.getWeek());

			todo.setStudent(em.find(Student.class, toDoDTO.getStudentId()));
			todo.setTeam(em.find(Team.class, toDoDTO.getTeamId()));
			todo.setTutor(em.find(Tutor.class, toDoDTO.getTutorId()));

			em.merge(todo);

			tx.commit();
		} 
		catch (Throwable t) {
			t.printStackTrace();
			tx.rollback();
			return false;
		} 
		finally {
			em.close();
		}
		
		try {
			
			if (todo.getStudent().isEmailNotification()) {
				
				String emailAddress = todo.getStudent().getEmail();
				String subject = "Updated to-do on ConsultTime!";
				String body = "Tutor: " + todo.getTutor().getFirstName() + " " + todo.getTutor().getLastName() + " (" + todo.getTutor().getUserName() + ")\n";
				body = body + "Project: " + todo.getTeam().getProject().getTitle() + "\n";
				body = body + "Team: " + todo.getTeam().getName() + "\n";
				body = body + "Student: " + todo.getStudent().getFirstName() + " " + todo.getStudent().getLastName() + " (" + todo.getStudent().getUserName() + ")\n\n";
				body = body + "To-do: \n";
				body = body + "Date: " + todo.getDate().toString() + "\n";
				body = body + "Title: " + todo.getTitle() + "\n";
				body = body + "Week: " + String.valueOf(todo.getWeek()) + "\n\n";
				body = body + todo.getDescription();
				
				EmailProvider.sendEmail(emailAddress, subject, body);
			}
		} catch (Throwable t) {
			t.printStackTrace();
		}
		
		return true;
		
	}
	
	@Override
	public Boolean deleteToDo(long toDoId) {

		EntityManager em = entityManager();
		EntityTransaction tx = em.getTransaction();

		try {
			tx.begin(); 
			em.remove(em.find(ToDo.class, toDoId));
			tx.commit();
			return true;
		} 
		catch (Throwable t) {
			t.printStackTrace();
			tx.rollback();
			return false;
		} 
		finally {
			em.close();
		}
	}

	private ToDoDTO createToDoDTO(ToDo toDo) {
		return new ToDoDTO(toDo.getTodoId(), toDo.getTitle(), toDo.getDate(), toDo.getWeek(), toDo.getDescription(), toDo.getStudent().getUserId(), toDo.getTeam().getTeamId(), toDo.getTutor().getUserId());
	}
}
